/* Copyright (C) 2008, 2009, 2010 Faindu GmbH, Switzerland.
* All Rights Reserved. The following is Source Code and is subject to all restrictions 
* on such code as contained in the license accompanying this project. */
package blocstac.editimage.crop
{

import blocstac.editimage.base.ImageOperation;
import blocstac.editimage.base.StateManager;
import blocstac.editimage.base.ViewModel;

import flash.display.Bitmap;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.ui.Keyboard;

/**
 * The user drags these "buttons" to edit the image.
 */
public class CropTool extends Sprite
{
	
	function CropTool(stateManager:StateManager, cropComponent:Sprite, rotateComponent:Sprite, imageComponent:Bitmap, addCropButtons:Function, 
		hideCropButtons:Function, updateButtonPosition:Function) {
		_stateManager = stateManager
		_cropComponent = cropComponent
		_rotateComponent = rotateComponent
		_imageComponent = imageComponent
		_addCropButtons = addCropButtons
		_hideCropButtons = hideCropButtons
		_updateButtonPosition = updateButtonPosition
	}
	
	//--------------------------------------------------------------------------
    //
    //  Variables
    //
    //--------------------------------------------------------------------------
	private var _stateManager:StateManager
	
	private var _cropComponent:Sprite
	private var _rotateComponent:Sprite
	private var _imageComponent:Bitmap
	private var _toolsComponent:Sprite
	private var _visibleWindow:Sprite
	private var _cropMask:CropMask
	
	private var _addCropButtons:Function
	private var _hideCropButtons:Function
	private var _updateButtonPosition:Function
	
	private var _componentWidth:Number
	private var _componentHeight:Number
	
	//--------------------------------------------------------------------------
	//
	//  Methods
	//
	//--------------------------------------------------------------------------
	public function init(toolsComponent:Sprite): void {
		_toolsComponent = toolsComponent
		_cropComponent.addChild(this)

		_visibleWindow = new Sprite()
		_visibleWindow.buttonMode = true
		_visibleWindow.mouseChildren = false
		_cropComponent.addChild(_visibleWindow)

		setupLurkingMode()
	}
	
	public function updateEditState():void {
		if (_stateManager.editState.isEditable) {
			_rotateComponent.addEventListener(MouseEvent.CLICK, goToCropMode)
		} else {
			_rotateComponent.removeEventListener(MouseEvent.CLICK, goToCropMode)
			tearDownEditMode()
			_stateManager.interactionEnds(null)
		}
	}	
	
	private function goToCropMode(mouseEvent:MouseEvent):void {
		if (_stateManager.interactionStarts()) {
			tearDownLurkingMode()
			setupEditMode()
		}
	}
	
	//--------------------------------------------------------------------------
	//
	//  Lurking mode
	//
	//--------------------------------------------------------------------------
	private function setupLurkingMode():void {
		_toolsComponent.visible = true
	}
	
	private function tearDownLurkingMode():void {
		_toolsComponent.visible = false
	}

	//--------------------------------------------------------------------------
	//
	//  Edit mode
	//
	//--------------------------------------------------------------------------
	private function setupEditMode():void {
		var viewModel:ViewModel = _stateManager.viewModel
		_cropMask = new CropMask(this, viewModel.componentWidth, viewModel.componentHeight, _visibleWindow, _updateButtonPosition)
		_cropMask.init()
		_cropComponent.addEventListener(KeyboardEvent.KEY_DOWN, keyHandler)
		stage.stageFocusRect = false
		stage.focus = _cropComponent
		addChild(_cropMask)
		mask = _cropMask

		// drag & drop mask
		_visibleWindow.addEventListener(MouseEvent.MOUSE_DOWN, dragMaskHandler)
		addEventListener(MouseEvent.MOUSE_DOWN, stopMouseEventHandler)
		
		_addCropButtons(applyButtonHandler, cancelButtonHandler)
	}
	
	private function tearDownEditMode():void {
		mask = null
		if (_cropMask) {
			removeChild(_cropMask)
			_cropComponent.removeEventListener(KeyboardEvent.KEY_DOWN, keyHandler)
			_cropMask.dispose()
			_cropMask = null
		}
		
		_hideCropButtons()
		
		_visibleWindow.removeEventListener(MouseEvent.MOUSE_DOWN, dragMaskHandler)
		removeEventListener(MouseEvent.MOUSE_DOWN, stopMouseEventHandler)
	}
	
	private function stopMouseEventHandler(mouseEvent:MouseEvent):void {
		mouseEvent.stopImmediatePropagation()
	}
	
	private function keyHandler(keyboardEvent:KeyboardEvent):void {
		var keyCode:uint = keyboardEvent.keyCode
		switch (keyCode) {
			case Keyboard.ENTER: cropImage()
			case Keyboard.ESCAPE: cancelCropping()
		}
	}
	
	private function applyButtonHandler(mouseEvent:MouseEvent):void {
		// otherwise, setupLurkingMode adds listeners startInteractionHandler which is immediatelly triggered with the same mouseEvent
		mouseEvent.stopImmediatePropagation()
		cropImage()
	}

	private function cropImage():void {
		var cropMask:Rectangle = _cropMask.getMask()
		var imageToStage:Matrix = _imageComponent.transform.concatenatedMatrix
		var stageToCropTool:Matrix = transform.concatenatedMatrix
		stageToCropTool.invert()
		var transformImageForCrop:Matrix = imageToStage
		transformImageForCrop.concat(stageToCropTool)
		transformImageForCrop.translate(-cropMask.x, -cropMask.y)
		
		_stateManager.viewModel.scaleToImageSize(transformImageForCrop, cropMask)
		var op:ImageOperation = new CropOperation(cropMask, transformImageForCrop)
		tearDownEditMode()
		setupLurkingMode()
		_stateManager.interactionEnds(op)
	}

	private function cancelButtonHandler(mouseEvent:MouseEvent):void {
		// otherwise, setupLurkingMode adds listeners startInteractionHandler which is immediatelly triggered with the same mouseEvent
		mouseEvent.stopImmediatePropagation()
		cancelCropping()
	}

	private function cancelCropping():void {
		tearDownEditMode()
		setupLurkingMode()
		_stateManager.interactionEnds(null)
	}
	
	//--------------------------------------------------------------------------
	//
	//  Drag & Drop
	//
	//--------------------------------------------------------------------------	
	private function dragMaskHandler(mouseEvent:MouseEvent):void {
		_cropComponent.addEventListener(MouseEvent.MOUSE_MOVE, moveMaskHandler)
		_cropComponent.addEventListener(MouseEvent.MOUSE_UP, endDragginHandler)
		_cropComponent.addEventListener(MouseEvent.ROLL_OUT, endDragginHandler)
		stage.addEventListener(Event.MOUSE_LEAVE, endDragginHandler)
		
		_cropMask.initMaskMove(mouseEvent.localX, mouseEvent.localY)
	}
	
	private function moveMaskHandler(mouseEvent:MouseEvent):void {
		_cropMask.moveRelative(mouseEvent.localX, mouseEvent.localY)
	}
	
	private function endDragginHandler(event:Event):void {
		_cropComponent.removeEventListener(MouseEvent.MOUSE_MOVE, moveMaskHandler)
		_cropComponent.removeEventListener(MouseEvent.MOUSE_UP, endDragginHandler)
		_cropComponent.removeEventListener(MouseEvent.ROLL_OUT, endDragginHandler)
		stage.removeEventListener(Event.MOUSE_LEAVE, endDragginHandler)
	}

	//--------------------------------------------------------------------------
	//
	//  Update
	//
	//--------------------------------------------------------------------------
	public function update():void {
	}
	
	public function buttonPosition():Point {
		var cropMask:Rectangle = _cropMask.getMask()
		if (cropMask.width > 70) {
			return new Point(cropMask.x+cropMask.width-59, cropMask.y+cropMask.height+1)
		}
		return new Point(cropMask.x+8, cropMask.y+cropMask.height+1)
	}
	
}
}